home *** CD-ROM | disk | FTP | other *** search
/ Chip: Internet / Chip Internet.iso / viewer / sox7dos / hcom.c < prev    next >
Text File  |  1993-02-11  |  11KB  |  476 lines

  1. /*
  2.  * September 25, 1991
  3.  * Copyright 1991 Guido van Rossum And Sundry Contributors
  4.  * This source code is freely redistributable and may be used for
  5.  * any purpose.  This copyright notice must be maintained. 
  6.  * Guido van Rossum And Sundry Contributors are not responsible for 
  7.  * the consequences of using this software.
  8.  */
  9.  
  10. /*
  11.  * Sound Tools Macintosh HCOM format.
  12.  * These are really FSSD type files with Huffman compression,
  13.  * in MacBinary format.
  14.  * To do: make the MacBinary format optional (so that .data files
  15.  * are also acceptable).  (How to do this on output?)
  16.  */
  17.  
  18. #include "st.h"
  19.  
  20. #ifdef __STDC__
  21. #include <string.h>
  22. /*
  23. #include <stdlib.h>
  24. */
  25. #else
  26. IMPORT char *malloc(), *realloc();
  27. #endif
  28.  
  29. /* Dictionary entry for Huffman (de)compression */
  30. typedef struct {
  31.     long frequ;
  32.     short dict_leftson;
  33.     short dict_rightson;
  34. } dictent;
  35.  
  36. /* Private data used by reader */
  37. struct readpriv {
  38.     /* Static data from the header */
  39.     dictent *dictionary;
  40.     long checksum;
  41.     int deltacompression;
  42.     /* Engine state */
  43.     long huffcount;
  44.     long cksum;
  45.     int dictentry;
  46.     int nrbits;
  47.     unsigned long current;
  48.     short sample;
  49. };
  50.  
  51. /*void*/ hcomstartread(ft)
  52. ft_t ft;
  53. {
  54.     struct readpriv *p = (struct readpriv *) ft->priv;
  55.     int i;
  56.     char buf[4];
  57.     unsigned long datasize, rsrcsize;
  58.     unsigned long huffcount, checksum, compresstype, divisor;
  59.     unsigned short dictsize;
  60.  
  61.     /* Skip first 65 bytes of header */
  62.     skipbytes(ft, 65);
  63.  
  64.     /* Check the file type (bytes 65-68) */
  65.     if (fread(buf, 1, 4, ft->fp) != 4 || strncmp(buf, "FSSD", 4) != 0)
  66.         fail("Mac header type is not FSSD");
  67.  
  68.     /* Skip to byte 83 */
  69.     skipbytes(ft, 83-69);
  70.  
  71.     /* Get essential numbers from the header */
  72.     datasize = rblong(ft); /* bytes 83-86 */
  73.     rsrcsize = rblong(ft); /* bytes 87-90 */
  74.  
  75.     /* Skip the rest of the header (total 128 bytes) */
  76.     skipbytes(ft, 128-91);
  77.  
  78.     /* The data fork must contain a "HCOM" header */
  79.     if (fread(buf, 1, 4, ft->fp) != 4 || strncmp(buf, "HCOM", 4) != 0)
  80.         fail("Mac data fork is not HCOM");
  81.  
  82.     /* Then follow various parameters */
  83.     huffcount = rblong(ft);
  84.     checksum = rblong(ft);
  85.     compresstype = rblong(ft);
  86.     if (compresstype > 1)
  87.         fail("Bad compression type in HCOM header");
  88.     divisor = rblong(ft);
  89.     if (divisor == 0 || divisor > 4)
  90.         fail("Bad sampling rate divisor in HCOM header");
  91.     dictsize = rbshort(ft);
  92.  
  93.     /* Translate to sox parameters */
  94.     ft->info.style = UNSIGNED;
  95.     ft->info.size = BYTE;
  96.     ft->info.rate = 22050 / divisor;
  97.     ft->info.channels = 1;
  98.  
  99.     /* Allocate memory for the dictionary */
  100.     p->dictionary = (dictent *) malloc(511 * sizeof(dictent));
  101.     if (p->dictionary == NULL)
  102.         fail("can't malloc memory for Huffman dictionary");
  103.  
  104.     /* Read dictionary */
  105.     for(i = 0; i < dictsize; i++) {
  106.         p->dictionary[i].dict_leftson = rbshort(ft);
  107.         p->dictionary[i].dict_rightson = rbshort(ft);
  108.         /*
  109.         report("%d %d",
  110.                p->dictionary[i].dict_leftson,
  111.                p->dictionary[i].dict_rightson);
  112.                */
  113.     }
  114.     skipbytes(ft, 1); /* skip pad byte */
  115.  
  116.     /* Initialized the decompression engine */
  117.     p->checksum = checksum;
  118.     p->deltacompression = compresstype;
  119.     if (!p->deltacompression)
  120.         report("HCOM data using value compression");
  121.     p->huffcount = huffcount;
  122.     p->cksum = 0;
  123.     p->dictentry = 0;
  124.     p->nrbits = -1; /* Special case to get first byte */
  125. }
  126.  
  127. /*void*/ skipbytes(ft, n)
  128. ft_t ft;
  129. int n;
  130. {
  131.     while (--n >= 0) {
  132.         if (getc(ft->fp) == EOF)
  133.             fail("unexpected EOF in Mac header");
  134.     }
  135. }
  136.  
  137. int hcomread(ft, buf, len)
  138. ft_t ft;
  139. long *buf, len;
  140. {
  141.     register struct readpriv *p = (struct readpriv *) ft->priv;
  142.     int done = 0;
  143.  
  144.     if (p->nrbits < 0) {
  145.         /* The first byte is special */
  146.         if (p->huffcount == 0)
  147.             return 0; /* Don't know if this can happen... */
  148.         p->sample = getc(ft->fp);
  149.         if (p->sample == EOF)
  150.             fail("unexpected EOF at start of HCOM data");
  151.         *buf++ = (p->sample - 128) * 0x1000000;
  152.         p->huffcount--;
  153.         p->nrbits = 0;
  154.         done++;
  155.         len--;
  156.         if (len == 0)
  157.             return done;
  158.     }
  159.  
  160.     while (p->huffcount > 0) {
  161.         if(p->nrbits == 0) {
  162.             p->current = rblong(ft);
  163.             if (feof(ft->fp))
  164.                 fail("unexpected EOF in HCOM data");
  165.             p->cksum += p->current;
  166.             p->nrbits = 32;
  167.         }
  168.         if(p->current & 0x80000000) {
  169.             p->dictentry =
  170.                 p->dictionary[p->dictentry].dict_rightson;
  171.         } else {
  172.             p->dictentry =
  173.                 p->dictionary[p->dictentry].dict_leftson;
  174.         }
  175.         p->current = p->current << 1;
  176.         p->nrbits--;
  177.         if(p->dictionary[p->dictentry].dict_leftson < 0) {
  178.             short datum;
  179.             datum = p->dictionary[p->dictentry].dict_rightson;
  180.             if (!p->deltacompression)
  181.                 p->sample = 0;
  182.             p->sample = (p->sample + datum) & 0xff;
  183.             p->huffcount--;
  184.             if (p->sample == 0)
  185.                 *buf++ = -127 * 0x1000000;
  186.             else
  187.                 *buf++ = (p->sample - 128) * 0x1000000;
  188.             p->dictentry = 0;
  189.             done++;
  190.             len--;
  191.             if (len == 0)
  192.                 break;
  193.         }
  194.     }
  195.  
  196.     return done;
  197. }
  198.  
  199. /*void*/ hcomstopread(ft) 
  200. ft_t ft;
  201. {
  202.     register struct readpriv *p = (struct readpriv *) ft->priv;
  203.  
  204.     if (p->huffcount != 0)
  205.         fail("not all HCOM data read");
  206.     if(p->cksum != p->checksum)
  207.         fail("checksum error in HCOM data");
  208.     free((char *)p->dictionary);
  209.     p->dictionary = NULL;
  210. }
  211.  
  212. struct writepriv {
  213.     unsigned char *data;    /* Buffer allocated with malloc */
  214.     unsigned int size;    /* Size of allocated buffer */
  215.     unsigned int pos;    /* Where next byte goes */
  216. };
  217.  
  218. #define BUFINCR (10*BUFSIZ)
  219.  
  220. /*void*/ hcomstartwrite(ft) 
  221. ft_t ft;
  222. {
  223.     register struct writepriv *p = (struct writepriv *) ft->priv;
  224.  
  225.     switch (ft->info.rate) {
  226.     case 22050:
  227.     case 22050/2:
  228.     case 22050/3:
  229.     case 22050/4:
  230.         break;
  231.     default:
  232.         fail("unacceptable output rate for HCOM: try 5512, 7350, 11025 or 22050 hertz");
  233.     }
  234.     ft->info.size = BYTE;
  235.     ft->info.style = UNSIGNED;
  236.     ft->info.channels = 1;
  237.  
  238.     p->size = BUFINCR;
  239.     p->pos = 0;
  240.     p->data = (unsigned char *) malloc(p->size);
  241.     if (p->data == NULL)
  242.         fail("can't malloc buffer for uncompressed HCOM data");
  243. }
  244.  
  245. /*void*/ hcomwrite(ft, buf, len)
  246. ft_t ft;
  247. long *buf, len;
  248. {
  249.     register struct writepriv *p = (struct writepriv *) ft->priv;
  250.     long datum;
  251.  
  252.     if (p->pos + len > p->size) {
  253.         p->size = ((p->pos + len) / BUFINCR + 1) * BUFINCR;
  254.         p->data = (unsigned char *) realloc(p->data, p->size);
  255.         if (p->data == NULL)
  256.             fail("can't realloc buffer for uncompressed HCOM data");
  257.     }
  258.  
  259.     while (--len >= 0) {
  260.         datum = *buf++;
  261.         datum >>= 24;
  262.         datum ^= 128;
  263.         p->data[p->pos++] = datum;
  264.     }
  265. }
  266.  
  267. /*void*/ hcomstopwrite(ft) 
  268. ft_t ft;
  269. {
  270.     register struct writepriv *p = (struct writepriv *) ft->priv;
  271.     unsigned char *data = p->data;
  272.     long len = p->pos;
  273.  
  274.     /* Compress it all at once */
  275.     compress(&data, &len, (double) ft->info.rate);
  276.     free((char *) p->data);
  277.  
  278.     /* Write the header */
  279.     (void) fwrite("\000\001A", 1, 3, ft->fp); /* Dummy file name "A" */
  280.     padbytes(ft, 65-3);
  281.     (void) fwrite("FSSD", 1, 4, ft->fp);
  282.     padbytes(ft, 83-69);
  283.     wblong(ft, (unsigned long) len); /* data size */
  284.     wblong(ft, (unsigned long) 0); /* rsrc size */
  285.     padbytes(ft, 128 - 91);
  286.     if (ferror(ft->fp))
  287.         fail("write error in HCOM header");
  288.  
  289.     /* Write the data fork */
  290.     if (fwrite((char *) data, 1, (int)len, ft->fp) != len)
  291.         fail("can't write compressed HCOM data");
  292.     free((char *) data);
  293.  
  294.     /* Pad the data fork to a multiple of 128 bytes */
  295.     padbytes(ft, 128 - (int) (len%128));
  296. }
  297.  
  298. /*void*/ padbytes(ft, n)
  299. ft_t ft;
  300. int n;
  301. {
  302.     while (--n >= 0)
  303.         putc('\0', ft->fp);
  304. }
  305.  
  306.  
  307. /* XXX This uses global variables -- one day these should all be
  308.    passed around in a structure instead. */
  309.  
  310. void putlong(c, v)
  311. unsigned char *c;
  312. long v;
  313. {
  314.   *c++ = (v >> 24) & 0xff;
  315.   *c++ = (v >> 16) & 0xff;
  316.   *c++ = (v >> 8) & 0xff;
  317.   *c++ = v & 0xff;
  318. }
  319.  
  320. void putshort(c, v)
  321. unsigned char *c;
  322. short v;
  323. {
  324.   *c++ = (v >> 8) & 0xff;
  325.   *c++ = v & 0xff;
  326. }
  327.  
  328. dictent dictionary[511];
  329. dictent *de;
  330. long codes[256];
  331. long codesize[256];
  332. long checksum;
  333.  
  334. void makecodes(e, c, s, b)
  335. int e, c, s, b;
  336. {
  337.   if(dictionary[e].dict_leftson < 0) {
  338.     codes[dictionary[e].dict_rightson] = c;
  339.     codesize[dictionary[e].dict_rightson] = s;
  340.   } else {
  341.     makecodes(dictionary[e].dict_leftson, c, s + 1, b << 1);
  342.     makecodes(dictionary[e].dict_rightson, c + b, s + 1, b << 1);
  343.   }
  344. }
  345.  
  346. long curword;
  347. int nbits;
  348.  
  349. void putcode(c, df)
  350. unsigned char c;
  351. unsigned char ** df;
  352. {
  353. long code, size;
  354. int i;
  355.   code = codes[c];
  356.   size = codesize[c];
  357.   for(i = 0; i < size; i++) {
  358.     curword = (curword << 1);
  359.     if(code & 1) curword += 1;
  360.     nbits++;
  361.     if(nbits == 32) {
  362.       putlong(*df, curword);
  363.       checksum += curword;
  364.       (*df) += 4;
  365.       nbits = 0;
  366.       curword = 0;
  367.     }
  368.     code = code >> 1;
  369.   }
  370. }
  371.  
  372. /*void*/ compress(df, dl, fr)
  373. unsigned char **df;
  374. long *dl;
  375. float fr;
  376. {
  377.   long samplerate;
  378.   unsigned char *datafork = *df;
  379.   unsigned char *ddf;
  380.   short dictsize;
  381.   int frequtable[256];
  382.   int i, sample, j, k, d, l, frequcount;
  383.  
  384.   sample = *datafork;
  385.   for(i = 0; i < 256; i++) frequtable[i] = 0;
  386.   for(i = 1; i < *dl; i++) {
  387.     d = datafork[i] - sample & 0xff;
  388.     sample = datafork[i];
  389.     datafork[i] = d;
  390.     frequtable[d]++;
  391.   }
  392.   de = dictionary;
  393.   for(i = 0; i < 256; i++) if(frequtable[i] != 0) {
  394.     de->frequ = -frequtable[i];
  395.     de->dict_leftson = -1;
  396.     de->dict_rightson = i;
  397.     de++;
  398.   }
  399.   frequcount = de - dictionary;
  400.   for(i = 0; i < frequcount; i++) {
  401.     for(j = i + 1; j < frequcount; j++) {
  402.       if(dictionary[i].frequ > dictionary[j].frequ) {
  403.         k = dictionary[i].frequ;
  404.         dictionary[i].frequ = dictionary[j].frequ;
  405.         dictionary[j].frequ = k;
  406.         k = dictionary[i].dict_leftson;
  407.         dictionary[i].dict_leftson = dictionary[j].dict_leftson;
  408.         dictionary[j].dict_leftson = k;
  409.         k = dictionary[i].dict_rightson;
  410.         dictionary[i].dict_rightson = dictionary[j].dict_rightson;
  411.         dictionary[j].dict_rightson = k;
  412.       }
  413.     }
  414.   }
  415.   while(frequcount > 1) {
  416.     j = frequcount - 1;
  417.     de->frequ = dictionary[j - 1].frequ;
  418.     de->dict_leftson = dictionary[j - 1].dict_leftson;
  419.     de->dict_rightson = dictionary[j - 1].dict_rightson;
  420.     l = dictionary[j - 1].frequ + dictionary[j].frequ;
  421.     for(i = j - 2; i >= 0; i--) {
  422.       if(l >= dictionary[i].frequ) break;
  423.       dictionary[i + 1] = dictionary[i];
  424.     }
  425.     i = i + 1;
  426.     dictionary[i].frequ = l;
  427.     dictionary[i].dict_leftson = j;
  428.     dictionary[i].dict_rightson = de - dictionary;
  429.     de++;
  430.     frequcount--;
  431.   }
  432.   dictsize = de - dictionary;
  433.   for(i = 0; i < 256; i++) {
  434.     codes[i] = 0;
  435.     codesize[i] = 0;
  436.   }
  437.   makecodes(0, 0, 0, 1);
  438.   l = 0;
  439.   for(i = 0; i < 256; i++) {
  440.       l += frequtable[i] * codesize[i];
  441.   }
  442.   l = (((l + 31) >> 5) << 2) + 24 + dictsize * 4;
  443.   report("  Original size: %6d bytes", *dl);
  444.   report("Compressed size: %6d bytes", l);
  445.   if((datafork = (unsigned char *)malloc((unsigned)l)) == NULL)
  446.     fail("can't malloc buffer for compressed HCOM data");
  447.   ddf = datafork + 22;
  448.   for(i = 0; i < dictsize; i++) {
  449.     putshort(ddf, dictionary[i].dict_leftson);
  450.     ddf += 2;
  451.     putshort(ddf, dictionary[i].dict_rightson);
  452.     ddf += 2;
  453.   }
  454.   *ddf++ = 0;
  455.   *ddf++ = *(*df)++;
  456.   checksum = 0;
  457.   nbits = 0;
  458.   curword = 0;
  459.   for(i = 1; i < *dl; i++) putcode(*(*df)++, &ddf);
  460.   if(nbits != 0) {
  461.     codes[0] = 0;
  462.     codesize[0] = 32 - nbits;
  463.     putcode(0, &ddf);
  464.   }
  465.   strncpy((char *) datafork, "HCOM", 4);
  466.   putlong(datafork + 4, *dl);
  467.   putlong(datafork + 8, checksum);
  468.   putlong(datafork + 12, 1L);
  469.   samplerate = 22050 / (long)fr;
  470.   putlong(datafork + 16, samplerate);
  471.   putshort(datafork + 20, dictsize);
  472.  
  473.   *df = datafork;
  474.   *dl = l;
  475. }
  476.